package cn.mw.cmdb.service.handler.monitorData;

import cn.mw.cmdb.entity.ItemDropInfo;
import cn.mw.cmdb.entity.ItemNameMapperInfo;
import cn.mw.cmdb.enums.ChartTypeEnum;
import cn.mw.cmdb.param.*;
import cn.mw.cmdb.param.zabbixResult.MwMonitorHistoryParam;
import cn.mw.cmdb.param.zabbixResult.MwZabbixItemResultParam;
import cn.mw.cmdb.processor.MonitorParamContext;
import cn.mw.cmdb.processor.MonitorProcessor;
import cn.mw.cmdb.service.MwMonitorProcessorConvert;
import cn.mw.cmdb.service.impl.CmdbServiceManage;
import cn.mw.cmdb.service.impl.MwInstanceMonitorManage;
import cn.mw.components.mongodb.page.MWPage;
import cn.mw.main.api.common.ZabbixDubboService;
import cn.mw.microMonitorCommon.entity.UnitResult;
import cn.mw.microMonitorCommon.entity.zabbix.MWZabbixAPIResult;
import cn.mw.microMonitorCommon.util.DateUtils;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson2.JSON;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.stream.Collectors;

import static cn.mw.cmdb.enums.MonitorMethodEnum.getItemResultByItemName;
import static cn.mw.cmdb.service.impl.InstanceMonitorServiceImpl.getValueMapIdInfo;
import static cn.mw.cmdb.util.CMDBCommonUtil.filterByValueSubstring;
import static cn.mw.cmdb.util.CMDBCommonUtil.sortByField;
import static cn.mw.cmdb.util.CustomPageUtil.getCustomPageInfo;
import static cn.mw.cmdb.util.ItemNameFilterUtil.itemNameFilter;
import static cn.mw.cmdb.util.ValConvertUtil.*;

/**
 * 最新数据查询
 */
@Slf4j
public class MonitorLastValueHandler implements HistoryHandlerProcessor<MwMonitorHistoryParam> {

    private CmdbServiceManage cmdbServiceManage;
    private ZabbixDubboService zabbixDubboService;
    private final String NORMAL = "NORMAL";//正常

    private final String interfaceName = "监控接口";
    private final String customNameKey = "devName";

    private final String fuzzyQuery = "fuzzyQuery";

    public MonitorLastValueHandler(CmdbServiceManage cmdbServiceManage, ZabbixDubboService zabbixDubboService) {
        this.cmdbServiceManage = cmdbServiceManage;
        this.zabbixDubboService = zabbixDubboService;
    }

    @Override
    public Object genMonitorData(MwMonitorHistoryParam param) throws Exception {
        String chartType = param.getChartType();
        ChartTypeEnum chartEnum = ChartTypeEnum.getChartEnumByName(chartType);
        Object resultData = new MwBaseMonitorDataResult();
        boolean isPie = false;
        //高级表格
        switch (chartEnum) {
            case advanceTable:
                resultData = getAdvanceTableResultData(param);
                break;
            default:
                resultData = getResultData(param);
        }
        return resultData;
    }


    /**
     * 获取最新数据lastValue
     * 主键类型(折线、柱状，topN，饼状，基础表格)
     */
    private MwBaseMonitorDataResult getResultData(MwMonitorHistoryParam param) throws Exception {
        MwBaseMonitorDataResult resultData = new MwBaseMonitorDataResult();
        param.setApplicationName(null);
        param.setHasDescription(true);
        MwMonitorProcessorConvert processorConvert = new MwMonitorProcessorConvert(cmdbServiceManage, zabbixDubboService);
        //获取查询监控参数context
        MonitorParamContext contextParam = processorConvert.getContextParam(param, null);
        //获取查询监控processor
        MonitorProcessor processor = processorConvert.getMonitorProcessor(param);
        //具先监控参数context中的MwInstanceZabbixParam参数
        contextParam.setQueryMonitorParam(param);
        List names = new ArrayList<>();
        Set<String> devNames = new HashSet<>();
        if (processor != null) {
//            log.info("contextParam::"+contextParam);
            //获取接口名称或分区名称
            names = processor.getNames(contextParam);
            if (CollectionUtils.isNotEmpty(names)) {
                for (Object obj : names) {
                    if (obj instanceof String) {
                        devNames.add(strValueConvert(obj));
                    } else {
                        ItemNameParam drop = (ItemNameParam) obj;
                        devNames.add(drop.getDevName());
                    }
                }
            }
            log.info("分区名称::" + names);
            param.setInterfaceDrops(new ArrayList<>(devNames));
            resultData.setInterfaceDrops(new ArrayList<>(devNames));
            List<ItemTotalInfoParam> itemTotalInfo = processor.getItemTotalInfo(contextParam);
            List<ItemDropInfo> itemInfos = param.getItemInfos();
            if(CollectionUtils.isNotEmpty(itemInfos) && itemInfos.size() == 1){
                resultData.setMergeItemName(true);
            }
            Set<String> valuemapidSet = itemInfos.stream().filter(s -> !Strings.isNullOrEmpty(s.getValuemapid())).map(s -> s.getValuemapid()).collect(Collectors.toSet());
            //item中valueMapId的映射数据
            Map<String, Map> valuemapidMap = getValueMapIdInfo(valuemapidSet, processor, contextParam);

            if (CollectionUtils.isNotEmpty(itemTotalInfo)) {
                for (ItemTotalInfoParam itemTotalInfoParam : itemTotalInfo) {
                    Object lastValue = itemTotalInfoParam.getLastValue();
                    String unit = itemTotalInfoParam.getUnit();
                    String valuemapid = itemTotalInfoParam.getValuemapid();
                    //lastValue单位转换
                    UnitResult unitResult = valueConvertUnit(unit, strValueConvert(lastValue), valuemapid, valuemapidMap);
                    itemTotalInfoParam.setLastValue(unitResult.getValue());
                    itemTotalInfoParam.setUnit(unitResult.getUnits());
                }
            }
            resultData.setItemTotalInfoList(itemTotalInfo);
        }
        return resultData;
    }

    /**
     * 高级表格查询数据
     */
    private Object getAdvanceTableResultData(MwMonitorHistoryParam param) throws Exception {

        AdvanceTableResultParam resultParam = new AdvanceTableResultParam();
        String assetsStatus = param.getAssetsStatus();
        if (!Strings.isNullOrEmpty(assetsStatus) && !NORMAL.equals(assetsStatus)) {
            //异常资产不返回数据
            return null;
        }
        long time1 = System.currentTimeMillis();
        String applicationName = param.getApplicationName();
        //监控设备
        List<String> devNames = param.getInterfaceDrops();
        //如果是默认布局，不进行dev查询，查询全部接口监控项
        if(param.isDefaultFlag()){
            devNames = new ArrayList<>();
        }
        //监控项
        List<String> itemNames = param.getItemNamesDropInfos();
        String customName = Strings.isNullOrEmpty(param.getCustomName()) ? interfaceName : param.getCustomName();
        List<MwAdvanceTableHeadParam> headList = new ArrayList<>();
        //判断是否有自定义接口名称
        if (!Strings.isNullOrEmpty(customName)) {
            MwAdvanceTableHeadParam headParam = new MwAdvanceTableHeadParam();
            headParam.setField(customNameKey);
            headParam.setHeaderName(customName);
            //加入表头数据
            headList.add(headParam);
        }
        MwInstanceMonitorManage monitorManage = new MwInstanceMonitorManage(zabbixDubboService);
        QueryMonitorParam queryMonitorParam = param;
        ParamContext paramContext = new ParamContext();
        //需要多线程处理的集合
        paramContext.setSubList(itemNames);
        paramContext.setApplicationName(applicationName);
        paramContext.setDevNames(devNames);
        //根据控项名称获取数据(多线程处理)
        List<Object> objects = monitorManage.handlerSubListMethodThread(queryMonitorParam, paramContext, getItemResultByItemName.getName());
        List<MwZabbixItemResultParam> lists = new ArrayList<>();
        //数据合并
        for (Object obj : objects) {
            MWZabbixAPIResult results = (MWZabbixAPIResult) obj;
            if (results!=null && results.getCode() == 0) {
                List<MwZabbixItemResultParam> lists01 = JSONObject.parseArray(JSON.toJSONString(results.getData()), MwZabbixItemResultParam.class);
                lists.addAll(lists01);
            }
        }
        //最后更新时间
        if (CollectionUtils.isNotEmpty(lists)) {
            OptionalLong maxDate = lists.stream().mapToLong(s -> longValueConvert(s.getLastclock())).max();
            String lastUpdateTime = DateUtils.formatDateTime(new Date(maxDate.getAsLong() * 1000));
            resultParam.setLastUpdateTime(lastUpdateTime);
        }
        long time2 = System.currentTimeMillis();
        log.info("获取高级表格查询数据耗时::" + (time2 - time1) + "ms;lists大小:" + lists.size());
        Set<String> valuemapidSet = lists.stream().map(s -> s.getValuemapid()).collect(Collectors.toSet());
        MwMonitorProcessorConvert processorConvert = new MwMonitorProcessorConvert(cmdbServiceManage, zabbixDubboService);
        //获取查询监控参数context
        MonitorParamContext contextParam = processorConvert.getContextParam(param, null);
        //获取查询监控processor
        MonitorProcessor processor = processorConvert.getMonitorProcessor(param);
        //监控参数context中的MwInstanceZabbixParam参数
        contextParam.setQueryMonitorParam(param);
        Map<String, Map> valuemapidMap = new HashMap<>();
        //itemName中文描述
        Map<String, String> itemNameMap = new HashMap<>();
        if (processor != null) {
            //获取item中valueMapId的映射数据
            valuemapidMap = getValueMapIdInfo(valuemapidSet, processor, contextParam);
            long time3 = System.currentTimeMillis();
            log.info("获取item中valueMapId的映射数据耗时::" + (time3 - time2) + "ms;");
            //获取itemName中文描述
            ItemNameMapperInfo itemParam = new ItemNameMapperInfo();
            itemParam.setItemList(new ArrayList<>(itemNames));
            List<ItemNameMapperInfo> itemNameMapperList = processor.getItemNameMapperList(itemParam);
            itemNameMap = itemNameMapperList.stream().filter(s -> !Strings.isNullOrEmpty(s.getItem())).collect(Collectors.toMap(s -> s.getItem(), s -> s.getDescrCn(), (o1, o2) -> o1));
            long time4 = System.currentTimeMillis();
            log.info("获取itemName中文描述耗时::" + (time4 - time3) + "ms");
        }
        for (String itemStr : itemNames) {
            MwAdvanceTableHeadParam headParam = new MwAdvanceTableHeadParam();
            headParam.setField(itemStr);
            if (itemNameMap != null && itemNameMap.containsKey(itemStr)) {
                headParam.setHeaderName(itemNameMap.get(itemStr));
            }
            //加入表头数据
            headList.add(headParam);
        }
        List<Map<String, MwMonitorLastValueParam>> mapList = new ArrayList<>();
        List<Map<String, Object>> queryList = new ArrayList<>();
        Map<String, Map> map = new HashMap();
        log.info("获取监控项集合：" + lists);
        Map<String, String> mapValue = new HashMap();
        for (MwZabbixItemResultParam requestZabbixParam : lists) {
            String name = requestZabbixParam.getName();
            String lastValue = strValueConvert(requestZabbixParam.getLastvalue());
            String valueType = requestZabbixParam.getValue_type();
            String valuemapid = requestZabbixParam.getValuemapid();

            MwMonitorLastValueParam valueParam = new MwMonitorLastValueParam();
            valueParam.setInitialVal(lastValue);
            valueParam.setValueType(valueType);
            //item监控项名称截取
            ItemNameParam itemNameParam = itemNameFilter(name);
            //监控项名称
            String itemName = itemNameParam.getItemName();
            //监控设备名称
            String devName = itemNameParam.getDevName();
            //lastValue单位转换
            UnitResult unitResult = valueConvertUnit(requestZabbixParam.getUnits(), lastValue, valuemapid, valuemapidMap);
            valueParam.setConvertVal(unitResult.getResult());
            Map<String, MwMonitorLastValueParam> maps = new HashMap();
            if (map.containsKey(devName)) {
                maps = map.get(devName);
                maps.put(itemName, valueParam);
                map.put(devName, maps);
            } else {
                maps = new HashMap();
                MwMonitorLastValueParam devNameParam = new MwMonitorLastValueParam();
                devNameParam.setConvertVal(devName);
                devNameParam.setInitialVal(devName);
                maps.put(customNameKey, devNameParam);
                maps.put(itemName, valueParam);
                map.put(devName, maps);
            }
            //不包含括号的监控项全名称
            String allItemName = devName + itemName;
            mapValue.put(allItemName, unitResult.getResult());
        }
        map.forEach((k, v) -> {
            mapList.add(v);
        });

        //数据转换，使用原始数据排序
        List<Map<String, Object>> maps = new ArrayList<>();
        for (Map<String, MwMonitorLastValueParam> ms : mapList) {
            Map viewMap = new HashMap();
            ms.forEach((k, v) -> {
                viewMap.put(k, v.getInitialVal());
            });
            maps.add(viewMap);
        }
        //排序
        if (Strings.isNullOrEmpty(param.getSortField())) {
            param.setSortField(customNameKey);
        }
        sortByField(maps, param.getSortField(), param.getSortMode());
        //数据格式转换，换成带单位的前端展示数据格式
        for (Map<String, Object> ms : maps) {
            //获取item监控项设备
            String itemDev = strValueConvert(ms.get(customNameKey));
            ms.forEach((k, v) -> {
                String itemName = k;
                //不包含括号的监控项全名称
                String allItemName = itemDev + itemName;
                if (mapValue != null && mapValue.containsKey(allItemName)) {
                    String convertVal = mapValue.get(allItemName);
                    ms.put(k, convertVal);
                }
            });
        }
        //查询搜索
        if (!Strings.isNullOrEmpty(param.getQueryValue())) {
            if (Strings.isNullOrEmpty(param.getQueryName())) {
                //全字段查询
                queryList = filterByValueSubstring(maps, param.getQueryValue());
            } else {
                for (Map<String, Object> mapInfo : maps) {
                    boolean isFlag = strValueConvert(mapInfo.get(param.getQueryName())).indexOf(param.getQueryValue()) != -1;
                    if (isFlag) {
                        queryList.add(mapInfo);
                    }
                }
            }
        } else {
            queryList = maps;
        }
        MWPage customPageInfo = getCustomPageInfo(param, queryList);
        resultParam.setHeadList(headList);
        resultParam.setDataList(customPageInfo);
        long time5 = System.currentTimeMillis();
        log.info("高级表格总耗时::" + (time5 - time1) + "ms");
        return resultParam;
    }

}
